package com.opencee.cloud.uaa.provider.service;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.opencee.cloud.autoconfigure.utils.RestTemplateUtil;
import com.opencee.cloud.base.api.IBaseAccountCredentialApi;
import com.opencee.cloud.base.api.IBaseUserApi;
import com.opencee.cloud.base.constants.BaseAccountType;
import com.opencee.cloud.base.entity.BaseAccountCredentialEntity;
import com.opencee.cloud.base.entity.BaseUserEntity;
import com.opencee.cloud.base.vo.BaseUserInfoVO;
import com.opencee.cloud.uaa.config.UaaProperties;
import com.opencee.cloud.uaa.constants.UaaConstants;
import com.opencee.common.security.SecurityUser;
import com.opencee.common.utils.RedisTemplateUtil;
import com.opencee.common.utils.WebUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * gitee第三方登录
 *
 * @author yadu
 */
@Service

public class GiteeUserDetailService implements UserDetailsService, ISocialService {

    private static final String TYPE = "gitee";


    @Autowired
    private IBaseAccountCredentialApi accountCredentialClient;
    @Autowired
    private IBaseUserApi userClient;
    @Autowired
    private RestTemplateUtil restTemplateUtil;
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;
    @Autowired
    private UaaProperties authProperties;

    /**
     * 账号密码登录认证信息获取
     *
     * @param code
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String code) throws UsernameNotFoundException {
        String token = getToken(code);
        JSONObject userInfo = getUserInfo(token);
        if (userInfo == null) {
            return null;
        }
        String uid = userInfo.getString("id");
        BaseAccountCredentialEntity account = accountCredentialClient.getBy(uid, BaseAccountType.GITEE.name()).getData();
        if (account == null) {
            String avatar = userInfo.getString("avatar_url");
            String name = userInfo.getString("name");
            BaseUserInfoVO user = new BaseUserInfoVO();
            user.setAvatar(avatar);
            user.setFullName(name);
            // 静默添加用户
            Long userId = userClient.save(user).getData();

            if (userId != null) {
                account = new BaseAccountCredentialEntity();
                account.setUserId(userId);
                account.setAccount(uid);
                account.setAccountType(BaseAccountType.GITEE.name());
                account.setCredentials(token);
                account.setRegisterIp(WebUtil.getClientIP(WebUtil.getHttpServletRequest()));
                account.setStatus(1);
                // 注册第三方登录账号
                accountCredentialClient.register(account);
            }
        }
        BaseUserEntity baseUserEntity = userClient.getById(account.getUserId()).getData();
        SecurityUser user = new SecurityUser();
        BeanUtils.copyProperties(baseUserEntity, user);
        user.setPassword(account.getCredentials());
        user.setCredentialsNonExpired(true);
        user.setAccountNonLocked(baseUserEntity.getStatus() != 2);
        user.setAccountEnabled(baseUserEntity.getStatus() == 1);
        return user;
    }

    /**
     * 认证类型
     *
     * @return
     */
    @Override
    public Boolean supports(String type) {
        return TYPE.equals(type);
    }

    /**
     * 获取登录地址
     * https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code
     *
     * @return
     */
    @Override
    public String getAuthorizeUrl() {
        UaaProperties.SocialClient client = authProperties.getSocial().get("gitee");
        String state = IdUtil.simpleUUID();
        String key = UaaConstants.CACHE_SOCIAL_CSRF_TOKEN + state;
        redisTemplateUtil.set(key, state, 5, TimeUnit.MINUTES);
        String clientId = client.getClientId();
        String redirectUri = client.getRedirectUri();
        String authorizationUri = client.getAuthorizationUri();
        String url = String.format("%s?client_id=%s&redirect_uri=%s&response_type=code&state=%s", authorizationUri, clientId, redirectUri, state);
        return url;
    }

    /**
     * 获取token
     * <p>
     * post https://gitee.com/oauth/token?grant_type=authorization_code&code={code}&client_id={client_id}&client_secret={client_secret}&redirect_uri={redirect_uri}
     *
     * @param code
     * @return
     */
    @Override
    public String getToken(String code) {
        UaaProperties.SocialClient client = authProperties.getSocial().get("gitee");
        String clientId = client.getClientId();
        String clientSecret = client.getClientSecret();
        String tokenUri = client.getTokenUri();
        String redirectUri = client.getRedirectUri();
        Map<String, String> params = new HashMap<>(8);
        params.put("grant_type", "authorization_code");
        params.put("code", code);
        params.put("client_id", clientId);
        params.put("client_secret", clientSecret);
        params.put("redirect_uri", redirectUri);
        JSONObject result = restTemplateUtil.post(tokenUri, new HashMap<>(0), params, JSONObject.class);
        String token = result.getString("access_token");
        return token;
    }

    /**
     * 获取用户信息
     * get https://gitee.com/api/v5/user?access_token={access_token}
     *
     * @param
     * @return
     */
    @Override
    public JSONObject getUserInfo(String token) {
        UaaProperties.SocialClient client = authProperties.getSocial().get("gitee");
        String userInfoUri = client.getUserInfoUri();
        if (StringUtils.isNotBlank(token)) {
            Map<String, String> params = new HashMap<>(8);
            params.put("access_token", "token");
            JSONObject result = restTemplateUtil.get(userInfoUri, new HashMap<>(6), params, JSONObject.class);
            return result;
        }
        return null;
    }
}
